#!/usr/bin/env ruby
=begin
Licence Information(MIT License)
  Copyright (c) 2007,2008 Katokichi.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Refer to:
   http://rmagick.rubyforge.org/Polaroid/polaroid.html
=end
require "optparse"
require "RMagick"
include Magick

class MagickCam
  def initialize(file)
    @file = file
    @image = Magick::Image.read(file).first

    # Change resolution to 72 dpi.
    @image.format = "RGB"
    @image.x_resolution = @image.y_resolution = 72
  end

  # Change the image's size
  def resize(len=480)
    len_f = len*1.0 # Convert to float
    if @image.rows > @image.columns
      @image.resize!(@image.columns*(len_f/@image.rows), len_f)
    else
      @image.resize!(len_f, @image.rows*(len_f/@image.columns))
    end
  end

  # Convert color to monochrome.
  def monochrome
    # Make a monochrome copy. See Image#quantize for details
    @image = @image.quantize(256, Magick::GRAYColorspace)
  end

  # Trim sides as it is square(fit to shorter side)
  def square
    if @image.rows > @image.columns
      shave_row = (@image.rows - @image.columns)/2
      shave_col = 0
    else
      shave_row = 0
      shave_col = (@image.columns - @image.rows)/2
    end
    @image.shave!(shave_col, shave_row)
  end

  # Effect like Polaroid(R)
  def polaroid(bg_color="none")
    rows = @image.rows
    cols = @image.columns

    @image = @image.enhance()

    # Replace edges from image to border
    #  18(16+2)pixel is 1/4 inch under 72dpi.
    @image.shave!(18, 18)

    # Make background photoframe
    back_array = ImageList.new
    back_grad = GradientFill.new(0, 0, 1, 0, "#f0f0ff", "#e9e9f9")
    top = Image.new(1, (rows-2)/2, back_grad)
    bottom = top.flip
    back_array << top << bottom
    back = back_array.append(true)
    back.resize!((cols-2), (rows-2), PointFilter)
    back.border!(1, 1, "#e5e5f3")
    back.border!(1, 1, "#e0e0ee")

    # Composite picture with photoframe
    @image = back.composite(@image, CenterGravity, OverCompositeOp)

    # Bend the image
    @image.background_color = "none"
    @image.opacity = 0 # is needed to consider transparency

    # vary according to taste
    amplitude = cols * 0.01
    wavelength = rows * 2

    @image.rotate!(90)
    @image = @image.wave(amplitude, wavelength)
    @image.rotate!(-90)

    # Make the shadow
    shadow = @image.flop
    shadow = shadow.colorize(1, 1, 1, "gray50")
    shadow.background_color = bg_color
    shadow.border!(10, 10, bg_color)
    shadow = shadow.blur_image(0, 3)

    # Composite image over shadow
    #  The y-axis adjustment can vary according to taste
    @image = shadow.composite(@image, -amplitude/2, 5, OverCompositeOp)

    # Bend image
    @image.rotate!(-5)
    @image.trim!
  end

  def write(filename)
    puts "Writing #{filename}"
    @image.write(filename)
  end
end

# Check the number of arguments.
if ARGV.size==0 then
  $stderr.puts parser.help
  exit 1
end

# Default settings
basefile = ""
suffix = "-print"
out_file = basefile
wipe_flag = 0
monochrome_flag = 0
square_flag = 0
nosuffix_flag = 0

# Parse and configure settings
parser = OptionParser.new
parser.banner = "Usage: #{File.basename($0)} [-mrw] [-o output_file] [-s suffix] image_file"
parser.on("-m","--monochrome",
          "Convert image color to monocherome."){
  monochrome_flag = 1
}
parser.on("-r", "--regular_square",
          "Cut a picture square"){
  square_flag = 1
}
parser.on("-s", "--suffix=suffix_string", String,
          "Specify the suffix of filename."){|arg|
  if arg == nil then
    $stderr.puts "-- s(suffix) requires suffix string."
    raise
  else
    suffix = arg
    nosuffix_flag = 0
  end
}
parser.on("-n", "--no_suffix",
          "Unset suffix to converted image.(The result may overwrite original)"){
  suffix = ""
  nosuffix_flag = 1
}
parser.on("-o", "--output=filename", String,
          "Specify the output filename."){|arg|
  if arg == nil then
    $stderr.puts "-- Output filename isn't set."
    raise
  else
    out_file = arg
    nosuffix_flag = 1
  end
}
parser.on("-w", "--wipe_original",
          "Remove original file after conversion."){
  wipe_flag = 1
}

# Start parsing
begin
  parser.parse!
rescue => err
  $stderr.puts err.message
  $stderr.puts parser.help
  exit 1
end

if nosuffix_flag==0 or out_file=="" then
  out_file = ARGV[0].sub(/\./, suffix+".")
end

#--------------------------------
# Main part
cam = MagickCam.new(ARGV[0])
cam.resize()
if monochrome_flag == 1 then
  cam.monochrome()
end
if square_flag == 1 then
  cam.square()
end
cam.polaroid("white")
cam.write(out_file)

if wipe_flag == 1 then
  if ARGV[0]==out_file then
    $stderr.puts "-- Ignore wipe flag. Because the output filename is the same with that of input file."
  else
    File.unlink(ARGV[0])
  end
end

exit 0

